package sis.studentinfo;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.logging.Handler;

import org.junit.Before;
import org.junit.Test;

import sis.util.TestHandler;

public class StudentTest {
	
	private static final double GRADE_TOLERANCE = 0.05;
	private Student student;
	
	@Before
	public void setUp() throws Exception {
		student = new Student("a");
	}

	@Test
	public void testCreate() {
		final String firstStudentName = "Jane Doe";
		Student student = new Student(firstStudentName);
		assertEquals(firstStudentName, student.getName());
		assertEquals("Jane", student.getFirstName());
		assertEquals("Doe", student.getLastName());
		assertEquals("", student.getMiddleName());
		
		Student secondStudent = new Student("Jone Blow");
		assertEquals("Jone Blow", secondStudent.getName());
		
		assertEquals(firstStudentName, student.getName());
	}
	
	@Test
	public void testStudentStatus() {
		assertEquals(0, student.getCredits());
		assertFalse("not enough credits for FT status", student.isFullTime());

		student.addCreadits(3);
		assertEquals(3, student.getCredits());
		assertFalse(student.isFullTime());
	
		student.addCreadits(4);
		assertEquals(7, student.getCredits());
		assertFalse(student.isFullTime());
		
		student.addCreadits(5);
		assertEquals(12, student.getCredits());
		assertTrue(student.isFullTime());
		
		assertEquals(Student.CREDITS_REQUIRED_FOR_FULL_TIME,
				student.getCredits());
	}
	
	@Test
	public void TestInState() {
		assertFalse(student.inInState());
		student.setState(Student.IN_STATE);
		assertTrue(student.inInState());
		student.setState("MD");
		assertFalse(student.inInState());
		
	}
	
	@Test
	public void testCalculateGpa() {
		this.assertGpa(student, 0.0);
		student.addGrade(Student.Grade.A);
		this.assertGpa(student, 4.0);
		student.addGrade(Student.Grade.B);
		this.assertGpa(student, 3.5);
		student.addGrade(Student.Grade.C);
		this.assertGpa(student, 3.0);
		student.addGrade(Student.Grade.D);
		this.assertGpa(student, 2.5);
		student.addGrade(Student.Grade.F);
		this.assertGpa(student, 2.0);
	}

	@Test
	public void testCalculateHonorsStudentGpa() {
		assertGpa(createHonorsStudent(Student.Grade.A), 5.0);
		assertGpa(createHonorsStudent(Student.Grade.B), 4.0);
		assertGpa(createHonorsStudent(Student.Grade.C), 3.0);
		assertGpa(createHonorsStudent(Student.Grade.D), 2.0);
		assertGpa(createHonorsStudent(Student.Grade.F), 0.0);
	}
	
	private void assertGpa(Student student, double expectedGpa) {
		assertEquals(expectedGpa, student.getGpa(), GRADE_TOLERANCE);
	}
	
	private Student createHonorsStudent(Student.Grade grade) {
		Student student = createHonorsStudent();
		student.addGrade(grade);
		return student;
	}
	
	private Student createHonorsStudent() {
		Student student = new Student("a");
		student.setGradingStrategy(new HonorsGradingStrategy());
		return student;
	}
	
	@Test
	public void testBadlyFormattedName() {
		Handler handler = new TestHandler();
		Student.logger.addHandler(handler);
		final String studentName = "a b c d";
		try {
			new Student(studentName);
			fail("expected exception form 4-part name");
		} catch (StudentNameFormatException e) {
			String message = String.format(Student.TOO_MANY_NAME_PARTS_MSG, 
					studentName, Student.MAX_NAME_PARTS);
			assertEquals(message, e.getMessage());
			assertEquals(message, ((TestHandler)handler).getMessage());
		}
	}

	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
